Log Format
The access log records every HTTP request handled by NGINX.
It is essential for:
- Security monitoring (attacks, scans, abuse)
- Performance analysis (latency, bottlenecks)
- Debugging application issues
- Traffic analytics
- Compliance and auditing
Each log entry represents one completed request.
How Access Logging Works Internally
- Client sends request
- NGINX processes request
- Response is sent
- After response, NGINX writes a log line using:
- A log format
- A log destination (file/syslog/stdout)
Core Directives for Access Logs
log_format (Define Log Structure)
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
Defines what data is logged and how it is structured
access_log (Enable Logging)
access_log /var/log/nginx/access.log main;
Uses:
- Log file path
- Log format name
Default NGINX Access Log Format (Combined)
NGINX’s default format is similar to Apache’s combined format:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
Example Log Entry
203.0.113.10 - - [22/Jan/2026:10:15:43 +0000]
"GET /login HTTP/1.1" 200 532
"https://example.com" "Mozilla/5.0"
Explanation of Common Access Log Variables
| Variable | Description | Security / Monitoring Use |
|---|---|---|
$remote_addr | Client IP address | Identify attackers |
$remote_user | Authenticated user | Audit |
$time_local | Request time | Incident timeline |
$request | Full request line | Detect exploits |
$status | HTTP response code | Error monitoring |
$body_bytes_sent | Response size | Traffic analysis |
$http_referer | Referrer URL | CSRF detection |
$http_user_agent | Client software | Bot detection |
Security-Focused Access Log Format (Recommended)
log_format security '$remote_addr '
'[$time_iso8601] '
'"$request" '
'$status '
'$request_time '
'"$http_user_agent"';
Example Entry
198.51.100.25 [2026-01-22T10:17:11+00:00]
"POST /login HTTP/1.1" 401 0.532 "curl/7.88.1"
Performance & Latency Monitoring Format
log_format performance '$remote_addr '
'"$request" '
'$status '
'rt=$request_time '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time';
Example
203.0.113.5 "GET /api HTTP/1.1" 200 rt=0.120 uct=0.003 uht=0.020 urt=0.115
| Field | Meaning |
|---|---|
rt | Total request time |
uct | Upstream connect time |
uht | Time to receive headers |
urt | Backend response time |
JSON Access Log Format (Best for Modern Monitoring)
log_format json escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"request_time":$request_time,'
'"user_agent":"$http_user_agent"'
'}';
Example JSON Log
{
"time":"2026-01-22T10:19:12+00:00",
"remote_addr":"192.0.2.15",
"method":"GET",
"uri":"/api/users",
"status":200,
"request_time":0.083,
"user_agent":"Mozilla/5.0"
}
Conditional Access Logging (Reduce Noise)
Log Only Errors (Status ≥ 400)
map $status $log_errors {
~^[45] 1;
default 0;
}
access_log /var/log/nginx/error_access.log security if=$log_errors;
Disable Access Logging (Static Content)
location /assets/ {
access_log off;
expires 30d;
}
Logging Real Client IP (Behind Proxy)
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
Then log:
log_format realip '$remote_addr "$request" $status';
Common Logging Mistakes
| Mistake | Impact |
|---|---|
| Logging without request time | Hard to debug slowness |
| Not using JSON logs | Painful parsing |
| Missing real IP | Wrong attacker identity |
| Logging everything | Disk exhaustion |
| No log rotation | Server crash |
Log Rotation (Essential)
NGINX does not rotate logs itself.
Use logrotate:
/var/log/nginx/*.log {
daily
rotate 14
compress
missingok
notifempty
create 0640 nginx adm
postrotate
systemctl reload nginx
endscript
}
Security-Recommended Access Log Format
log_format secure_json escape=json
'{'
'"time":"$time_iso8601",'
'"ip":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"rt":$request_time,'
'"ua":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.log secure_json;